#include<bits/stdc++.h>

using namespace std;
using ll = long long;
#define endl '\n'

struct Edge {
    int x, y, w;
    /**
     * less<T>规范的定义应该为 bool operator<(const T &e)const  不然最新的编译器会报CE
     * @param e
     * @return
     */
    bool operator<(const Edge &e) const {
        return w < e.w;
    }
} E[9] = {
        {1, 2, 1},
        {1, 3, 2},
        {2, 3, 6},
        {2, 4, 11},
        {3, 4, 9},
        {3, 5, 13},
        {4, 5, 7},
        {4, 6, 3},
        {5, 6, 4}


};

int Vertex[] = {1, 2, 3, 4, 5, 6};
int n = 6, m = 9;
int book[6];
const int maxn = 100;
int F[maxn];


/**
 * 并查集的初始化:把数组F[i](1<=i <=n )设置为F[i]=i
 * @param n
 */
void Init() {
    for (int i = 1; i <= n; i++)F[i] = i;
}

/**
 * 并查集找根节点：寻找x所在的那个树的树根
 * @param x
 * @return
 */
int Find(int x) {
    if (x == F[x]) {
        return x;//说明x就是树根
    } else {
        return F[x] = Find(F[x]);//递归的寻找 F[x]的根,路径压缩
    }
}
/**
 * 合并x,y所在的子树为一棵树
 * @param x
 * @param y
 * @return
 */
bool Merge(int x, int y) {
    int fx = Find(x);
    int fy = Find(y);
    if (fx == fy)return false;//不用合并,xy已经在一棵树上
    F[fy] = fx;//把 fy所在的子树都合并到fx这个树上，fx是合并后的树根
    return true;
}

/**
 * 计算连通分支数，（森林里树个数量）
 * @param n
 * @return
 */
int Count() {
    int cnt = 0;
    for (int i = 1; i <= n; i++) {
        if (F[i] == i) {
            ++cnt;
        }
    }
    return cnt;
}

/**
 * 最小生成树的克鲁斯卡尔算法（贪心算法）边集排序+并查集判环
 * 算法复杂度：mlogm（边集排序开销）+O(n)（并查集合并查找开销） 适合边较少的情况（稀疏图）
 */
int Kruskal() {
    sort(E, E + m);
    Init();
    int tot = 0, cnt = 0;
    for (int i = 0; i < m; i++) {
        if (Find(E[i].x) == Find(E[i].y))continue;
        tot += E[i].w;
        Merge(E[i].x, E[i].y);
        ++cnt;
        if (cnt == n - 1)break;
    }
    if (cnt != n - 1)return -1;//说明图不联通
    return tot;

}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);
    cout << Kruskal() << endl;
    return 0;
}
